use std::ops::Add;
use chrono::Local;

#[derive(Debug,Default)]
pub struct TcpTag {
    inner: String
}

impl TcpTag {
    pub fn string(&self) -> String {
        if let Some((_,str2)) = self.inner.split_once(":") {
            return str2.to_string();
        }

        self.inner.to_string()
    }

    pub fn is_response(&self) ->bool {
        if let Some((str2,_)) = self.inner.split_once(":") {
            if str2 == "response" {
                return true;
            }
        }

        false
    }
}

#[derive(Debug,Default)]
pub struct TcpData {
    id:   String,
    tag:  TcpTag,
    time: String,
    data: Vec<u8>,
}

impl TcpData {
    pub fn decode(data:Vec<u8>) -> Self {
        let mut result = TcpData::default();
        let mut str = String::from_utf8(data.clone()).unwrap();
        let arr:Vec<&str> = str.split("\r\n").collect();
        result.id = arr[0].to_string();
        result.tag = TcpTag{inner:arr[1].to_string()};
        result.time = arr[2].to_string();
        if arr.len() > 3 {
            let begin = "\r\n".len()*3 + result.id.len() + result.tag.string().len() +result.time.len();
            if data.len() > begin {
                let (_,d ) = data.split_at(begin);
                result.data = d.clone().to_vec();
            }
        }

        result
    }

    pub fn encode(tag:String,data:Vec<u8>) -> Self {
        let id = Local::now().timestamp_micros().to_string();

        let mut result = TcpData::default();
        result.id = id.clone();
        result.tag = TcpTag{inner:tag};
        result.data = data;
        result.time = id;

        result
    }


    pub fn bytes(&self) -> Vec<u8> {
        let str = "\r\n";
        let mut result = Vec::new();
        result.append(&mut self.id.clone().into_bytes());
        result.append(&mut str.to_string().into_bytes());
        result.append(&mut self.tag.string().into_bytes());
        result.append(&mut str.to_string().into_bytes());
        result.append(&mut self.time.clone().into_bytes());
        result.append(&mut str.to_string().into_bytes());
        result.append(&mut self.data.clone());

        result
    }


    pub fn string(&self) -> String {
        let mut str = String::new();
        str = str.add(self.id.as_str()).add("\r\n").
            add(self.tag.inner.as_str()).add("\r\n").
            add(self.time.as_str()).add("\r\n").
            add(String::from_utf8(self.data.clone()).unwrap().as_str());

        str
    }

    pub fn data(&self) -> &Vec<u8> {
        &self.data
    }


    pub fn id(&self) -> String {
        self.id.clone()
    }

    pub fn tag(&self) -> &TcpTag {
        &self.tag
    }

    pub fn response_data(&self,data:Vec<u8>) -> Self {
        let mut result = TcpData::default();
        result.id = self.id.to_string();
        result.tag = TcpTag{ inner:String::from("response:").add(self.tag.string().as_str())};
        result.time = Local::now().timestamp().to_string();
        result.data = data;

        result
    }
}

#[cfg(test)]
mod test {
    use crate::codes::tcp::TcpData;

    #[test]
    fn test() {
        let data = TcpData::encode(String::from("test"), "asdasdasdasdasdasd".to_string().into_bytes());
        println!("{}",data.string());
        println!();
        println!("{}",data.response_data("啊啊啊啊啊啊啊".to_string().into_bytes()).string());
        println!();
        let data = TcpData::decode(data.bytes());
        println!("{}",data.string())
    }
}

